home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / SDKs / AutoPay Developer's Kit / AutoPay Devel Kit (6.90) / AutoPay™ Development / other routines you may want / routines you may want.c
Encoding:
Text File  |  1995-11-02  |  12.0 KB  |  498 lines  |  [TEXT/MMCC]

  1.  
  2. // ****************************************************************
  3. //
  4. // Copyright 1995 Digital Money, Inc.
  5. // You may use this source code in your own applications.
  6. //
  7. // *******************************************************************
  8. //
  9. // Supplemental routines for use with Digital Money AutoPay Module.
  10. // These routines were written for Think C 5.0, modified to run under Metrowerks CodeWarrior,
  11. // and should be immediately useable with other C environments.
  12.  
  13. // Feel free to use these routines in you own applications.
  14. // See the AutoPay manual, Chapter 4, for more information.
  15.  
  16. // This file uses ANSI routines.
  17.  
  18. // Updated September 6, 1995.
  19. // *******************************************************************
  20.  
  21. // *******************************
  22. // THINGS YOU NEED TO PERSONALIZE:
  23. // *******************************
  24.  
  25. // Personalize the following three strings:
  26.  
  27. #define kTheCryptoKey         "Put your crypto key here!"
  28. #define kYourProgramName     "YourProgramNameHere"
  29. #define kOwnerResource        'xYxn'                    // This should match your 
  30.                                                 // application's owner resource
  31.                                                 // If you don't know what this is,
  32.                                                 // choose a random 4-char string.
  33. #include <Folders.h>
  34. #include <Files.h>
  35. #include <Script.h>
  36.  
  37. // The keyType structure. See the description below.
  38.  
  39. typedef struct
  40. {
  41.     char            name[60];
  42.     char            verificationCode[60];
  43.     char            serialNumber[30];
  44. }    keyType;
  45.  
  46. // *******************
  47. // Function prototypes
  48. // *******************
  49.  
  50. OSErr         readKeyFromDisk             (keyType *key);
  51. OSErr         writeKeyToDisk             (keyType *key);
  52. Boolean         isProgramRegistered         (void);
  53. char             *myEncrypt                (char *inputString, char *cryptoKey);
  54. OSErr         saveProgramAsRegistered     (char *theName);
  55. OSErr         saveSerialNumber             (char *theSerialNumber);
  56. void             drawSplashScreen             (int whichColorPictToUse, int whichBWPictToUse);
  57.  
  58. Boolean isProgramRegistered (void)
  59. {
  60.     keyType        theKey;
  61.     char            cryptoKey[50], whatItShouldBe[80];
  62.     OSErr        iErr;
  63.     
  64.     // EXPLANATION:
  65.     //
  66.     // This is a pretty straightforward locking/unlocking mechanism that you can use
  67.     // in your program to see whether a program has been registered (i.e. payed for)
  68.     // or not.
  69.     
  70.     // A brief description follows, but for more details, you should see
  71.     // your AutoPay Developer's Manual.
  72.     
  73.     // What happens is this. The program opens a "key file" which is stored
  74.     // in the preferences folder. The Key File has three components:
  75.     
  76.     //     The registration name :    the name of the user who paid for program
  77.     
  78.     //      The verification code :    a special code that is specific to
  79.     //                                  to the registration name. This proves the
  80.     //                                registration name hasn't been tampered with.
  81.                                     
  82.     //    The serial number        
  83.     
  84.     
  85.     
  86.     iErr=readKeyFromDisk(&theKey);
  87.     
  88.     if (iErr)
  89.     {
  90.         // add your own error handling here if desired
  91.     }
  92.     
  93.     if (strlen((char*)theKey.name)==0)
  94.     {
  95.         // Either the key file doesn't exist or the name has been tampered
  96.         // with. So treat this as an unregistered copy.
  97.         
  98.         return (false);
  99.     }
  100.     
  101.     // A name *does* exist. Now the program looks at the verification code. 
  102.     // There is some, *unobvious* cryptographic relationship between the name and
  103.     // the verification code, but only you as the developer knows it. This stops
  104.     // hackers from examining an officially registered copy of your app and figuring
  105.     // out how to write a "correct" result string based on a seed string of his choice.
  106.     
  107.     if (strlen((char*)theKey.verificationCode)==0)
  108.     {
  109.         return (false);
  110.     }
  111.         
  112.     strcpy(cryptoKey,kTheCryptoKey);
  113.     
  114.     // Feed the name into the encryption routine to find out what the
  115.     // verification code *should* be. Then see if it's a match.
  116.     
  117.     strcpy((char*)&whatItShouldBe, myEncrypt((char*)&theKey.name,cryptoKey) );
  118.     if ( strcmp    (
  119.             whatItShouldBe,            // If the resultString is
  120.             &theKey.verificationCode        // identical to what you'd expect to get
  121.                 ) == 0 )                 // given your program's cryptoKey,
  122.                                         
  123.         {    
  124.             return(true);                // then this is a valid, registered copy
  125.         }
  126.     else
  127.         {
  128.             return(false);                // ...otherwise it isn't
  129.         }
  130. }
  131.  
  132. OSErr saveSerialNumber (char *theSerialNumber)
  133. {
  134.     keyType theKey;
  135.     
  136.  
  137.     readKeyFromDisk(&theKey);
  138.     strcpy((char*)&theKey.serialNumber,theSerialNumber);
  139.     writeKeyToDisk(&theKey);
  140. }
  141.  
  142.  
  143.     
  144. OSErr saveProgramAsRegistered (char *theName)
  145. {
  146.     OSErr     iErr;
  147.     keyType theKey;
  148.     char     *theResult;
  149.     char    cryptoKey[50];
  150.     
  151.     // First the program stores the name string in the appropriate place.
  152.     
  153.     iErr=readKeyFromDisk(&theKey);
  154.     if (iErr)
  155.         return (iErr);
  156.         
  157.     // Next it stores the Verification Code, which is encrypted based on your
  158.     // cryptoKey. See the AutoPay manual for more information.
  159.     
  160.     strcpy(cryptoKey,kTheCryptoKey);
  161.     strcpy ((char*)&theKey.verificationCode, myEncrypt(theName,cryptoKey) );
  162.     
  163.     strcpy((char*)&theKey.name,theName);
  164.     iErr=writeKeyToDisk(&theKey);
  165.     if (iErr)
  166.         return (iErr);
  167.         
  168. }
  169.  
  170.  
  171. char *myEncrypt(char *inputString, char *cryptoKey)
  172. {
  173.     long     numCharsInInput;
  174.     int        cryptoCharToUse,i;
  175.     char    charToAdd;
  176.     char    *outputString;
  177.     
  178.     // Given an input string and a cryptoKey (know only to you)
  179.     // this routiner spits out an encrypted version of the input
  180.     // string. Later, you'll be able to compare say, a user's name
  181.     // and it's encrypted version to make sure the user's name hasn't been
  182.     // tampered with.
  183.     
  184.     outputString=NewPtr(strlen(inputString)+1);
  185.     
  186.     numCharsInInput=strlen(inputString);
  187.     cryptoCharToUse=0;
  188.     *outputString='\0';
  189.     
  190.     for (i=0; i<=numCharsInInput-1; i++)
  191.     {
  192.         
  193.         charToAdd=(inputString[i]^cryptoKey[cryptoCharToUse])+28; // ^ is exclusive OR
  194.         
  195.         charToAdd=charToAdd%33; // the remainder of the number after divided by 33
  196.         charToAdd=32+charToAdd;
  197.         outputString[i]=charToAdd;
  198.         
  199.         cryptoCharToUse++;
  200.         if (cryptoCharToUse>strlen(cryptoKey)-1)
  201.             cryptoCharToUse=0;
  202.     }
  203.  
  204.     outputString[i]='\0'; // make sure the output string is terminated with a null
  205.     
  206.     return (outputString);
  207. }
  208.  
  209.  
  210.  
  211. OSErr readKeyFromDisk (keyType *key)
  212. {
  213.  
  214.     OSErr    myErr;
  215.     short    myVRef, i;
  216.     long    myDirID;
  217.     FSSpec    mySpec;
  218.     char    myName[25];
  219.     short        myRef;
  220.     Handle    myHandle;
  221.     int        myRefNum, version;
  222.     long    len;
  223.     long    myLen[6];
  224.     
  225.     // find the "key" file in the system
  226.     
  227.     strcpy(myName,kYourProgramName);
  228.     strcat(myName," Key");
  229.     
  230.     // The "key file" will be stored in the Preferences folder 
  231.     // within the System folder
  232.     
  233.     myErr=FindFolder(kOnSystemDisk,kPreferencesFolderType,kDontCreateFolder, &myVRef, &myDirID);
  234.     
  235.     if (myErr==noErr)
  236.         myErr=FSMakeFSSpec(myVRef, myDirID, CtoPstr(myName), &mySpec);
  237.  
  238.     // If no "key file" exists, return a null key.
  239.     // This will happen the first time the user wants to register.
  240.     
  241.     if (myErr==fnfErr)
  242.     {
  243.         key->name[0]='\0';
  244.         key->verificationCode[0]='\0';
  245.         key->serialNumber[0]='\0';
  246.         return(noErr);
  247.     }
  248.     
  249.     if (myErr==noErr)
  250.         myRefNum=FSpOpenDF(&mySpec, fsRdWrPerm, &myRef);
  251.     else if (myErr!=eofErr) return(myErr);                    // error check
  252.  
  253.     
  254.     myErr=SetFPos(myRef, fsFromStart,0);
  255.     
  256.     if ((myErr!=noErr) && (myErr!=eofErr))
  257.          return(myErr);                                        // error check
  258.     
  259.     // Check the version number of the key file.
  260.     // This really has no use now, but may or may not come in handy in
  261.     // in the future, if you ever decide to change the file format of
  262.     // the key file.
  263.     
  264.     len=2;
  265.     if (myErr==noErr)
  266.     {
  267.         myErr=FSRead(myRef, &len, &version);
  268.     }
  269.     if (version!=1)
  270.         myErr=eofErr; // if this is not version 1, just pretend file doesn't exist
  271.     
  272.     len=sizeof(*key);    
  273.     
  274.     if (myErr==noErr)
  275.     {
  276.         myErr=FSRead(myRef, &len, key);
  277.     }
  278.     
  279.     
  280.     if ((myErr) && (myErr!=eofErr)) return(myErr);         // error check
  281.  
  282.     FSClose(myRef);
  283.     
  284.     return(noErr);
  285.       
  286. }
  287.  
  288. OSErr writeKeyToDisk (keyType *key)
  289. {
  290.     OSErr    myErr;
  291.     short    myVRef, i;
  292.     long    myDirID;
  293.     FSSpec    mySpec;
  294.     char    myName[25];
  295.     int        scrapInt;
  296.     short     myRef,myVol;
  297.     int        myRefNum;
  298.     long    len,fLength=0;
  299.  
  300.     strcpy(myName,kYourProgramName);
  301.     strcat(myName," Key");
  302.  
  303.     myErr=FindFolder(kOnSystemDisk,kPreferencesFolderType,kDontCreateFolder, &myVRef, &myDirID);
  304.     
  305.     if (myErr==noErr)
  306.         myErr=FSMakeFSSpec(myVRef, myDirID, CtoPstr(myName), &mySpec);
  307.  
  308.     if (myErr==fnfErr)
  309.     {
  310.         myErr= FSpCreate(&mySpec, kOwnerResource, 'pref', smSystemScript);
  311.         fLength=0;
  312.     }
  313.     
  314.     if (myErr==noErr)
  315.         myRefNum=FSpOpenDF(&mySpec, fsRdWrPerm, &myRef);
  316.     
  317.     
  318.     if (myErr==noErr)
  319.     {
  320.         myErr=SetFPos(myRef, fsFromStart, 0);        // write at beginning
  321.     }
  322.     
  323.     // Write the version number of the key file
  324.     // for future upgrade capability. This is version 1.
  325.     
  326.     len=2;
  327.     scrapInt=1;
  328.     if (myErr==noErr)
  329.     {
  330.         myErr= FSWrite (myRef, &len, &scrapInt);
  331.         fLength+=len;
  332.     }
  333.     
  334.     // write the actual key data structure
  335.     
  336.     len=sizeof(*key);
  337.     if (myErr==noErr)
  338.     {
  339.         myErr= FSWrite (myRef, &len, key);
  340.         fLength+=len;
  341.     }
  342.  
  343.     myErr=SetEOF(myRef, fLength);
  344.     if (myErr) return(myErr);
  345.     
  346.     if (myErr==noErr)
  347.     {
  348.         myErr=GetVRefNum(myRef, &myVol);                // find volume file is on
  349.     }
  350.     
  351.     if (myErr==noErr)
  352.     {
  353.         FSClose(myRef);
  354.         myErr=FlushVol(nil, myVol);                        // ... and flush it
  355.         if (myErr) return(myErr);
  356.     }
  357.       
  358.     return(myErr);
  359. }
  360.  
  361.  
  362. /********************************/
  363. //        drawSplashScreen        //
  364. /*******************************/
  365.  
  366. void drawSplashScreen (int whichColorPictToUse, int whichBWPictToUse)
  367. {
  368.  
  369.     GrafPtr        oldPort;
  370.     Boolean        userReacts, hasColor=false;
  371.     SysEnvRec    sysEnv;
  372.     Rect        r,winRect,textBox;
  373.     PicHandle    thePict;
  374.     int         screenWidth,screenHeight,pictWidth,pictHeight,winLeft,winTop;
  375.     WindowPtr    window;
  376.     short        oldFont,oldSize,curPnMode;
  377.     EventRecord    event;
  378.     keyType        theKey;
  379.     char        output[100];
  380.     
  381.     #define        SysEnvironsTrap            0xA090
  382.     #define        UnknownTrap                0xA89F
  383.  
  384.     GetPort(&oldPort);
  385.     
  386.     // First check to see if the computer has color display or not.
  387.     // This will help us decide whether to draw the color picture
  388.     // or the B&W picture.
  389.     
  390.     if ((long)NGetTrapAddress(SysEnvironsTrap, OSTrap) != (long)NGetTrapAddress(UnknownTrap, ToolTrap))
  391.     {
  392.         SysEnvirons(1, &sysEnv);
  393.         
  394.         // Check graphic's device depth    
  395.         if ((*((*((GDHandle)GetGDevice()))->gdPMap))->pixelSize > 1)    
  396.         {
  397.             hasColor = sysEnv.hasColorQD;                        // Does it have color?        
  398.         }
  399.     }
  400.         
  401.     if (hasColor)
  402.         thePict=GetPicture(whichColorPictToUse);        
  403.     else
  404.         thePict=GetPicture(whichBWPictToUse);
  405.  
  406.     r = (*thePict)->picFrame;
  407.     
  408.     pictWidth = r.right - r.left;        // calculate width of picture
  409.     pictHeight = r.bottom - r.top;        // calculate height of picture
  410.     
  411.     
  412.     screenWidth =(qd.screenBits.bounds).right;        // calculate width of screen
  413.     screenHeight =(qd.screenBits.bounds).bottom;    // calculate height of screen
  414.     
  415.     // Center the splash window on the screen:
  416.     
  417.     winLeft=(screenWidth/2)-(pictWidth/2);
  418.     winTop=(screenHeight/2)-(pictHeight/2);
  419.     SetRect(&winRect,winLeft,winTop,winLeft+pictWidth,winTop+pictHeight);
  420.     
  421.     // make a new, temporary window, just big enough to hold your
  422.     // splash screen picture
  423.     window = NewWindow(nil,&winRect,"\p",true,plainDBox,(WindowPtr)-1,false,0);
  424.     
  425.     SetPort(window);
  426.     DrawPicture( thePict,  &(window->portRect) );
  427.     
  428.     // Now draw your text ON TOP OF the picture.
  429.     
  430.     
  431.     TextFont(applFont);
  432.     TextFace(bold);
  433.     
  434.     readKeyFromDisk(&theKey);
  435.     
  436.     if (!isProgramRegistered())
  437.     {
  438.         
  439.         strcpy(output,"This program is not registered.\rYou can register immediately with Digital Money™.\rSee the Apple menu.");
  440.         
  441.         // You may want to change the coordinates where the text box is overlaid
  442.         // on picture window:
  443.         
  444.         TextSize(11);
  445.         SetRect(&textBox,window->portRect.left+2,window->portRect.bottom-80,window->portRect.right-2,window->portRect.bottom-30);
  446.         TextBox(output,strlen(output),&textBox,teJustLeft);
  447.     
  448.     }
  449.     else
  450.     {
  451.  
  452.         sprintf(output,"This copy is registered to %s.",(char*)&theKey.name);
  453.     
  454.         TextMode(srcBic); // reverse out the text you're about to draw
  455.         
  456.         // You may want to change the coordinates where the text is
  457.         // "reversed out" of window:
  458.         
  459.         MoveTo(2,window->portRect.bottom-45);
  460.         TextSize(10);
  461.         DrawText(output,0,strlen(output));
  462.         if (strlen((char*)&theKey.serialNumber))
  463.         {
  464.             sprintf(output,"Serial Number %s",(char*)&theKey.serialNumber);
  465.             MoveTo(2,window->portRect.bottom-30);
  466.         }
  467.     }
  468.     
  469.     SelectWindow(window);
  470.     
  471.     
  472.     // wait for the user to click the mouse or hit a key...
  473.     
  474.     userReacts=false;
  475.     do
  476.     {
  477.         if (WaitNextEvent(everyEvent, &event, 20, nil))
  478.         {    
  479.             switch (event.what)
  480.             {    
  481.                 case mouseDown:
  482.                 case keyDown:
  483.                 case autoKey:    
  484.                     userReacts=true;
  485.                     break;
  486.                 default:
  487.                     userReacts=false;
  488.                     break;
  489.             }
  490.         }
  491.     }
  492.     while (!userReacts);
  493.     
  494.     HideWindow(window);
  495.     DisposeWindow(window);
  496.     ReleaseResource((Handle)thePict);
  497. }    
  498.